package leducHoldem.Data;

import java.util.LinkedList;
import java.util.Stack;

public class Board extends AbstractBoard {

	public Move table;
	private Move[] playerCards;

	public LinkedList<Move> availableActions;

	public Stack<Move> history;

	protected int pot = 0;
	public int round = 1;
	public byte currentPlayer = 1;
	public int gainForPlayer1 = 0;

	public Board() {

		this.history = new Stack<Move>();
		this.availableActions = new LinkedList<Move>();

		placeAnte();

		generateAvailableActions();
	}

	public Board(Move firstCard, Move secondCard) {

		this.history = new Stack<Move>();
		this.availableActions = new LinkedList<Move>();
		this.playerCards = new Move[] { firstCard, secondCard };
		this.id = firstCard.toString();

		placeAnte();

		generateAvailableActions();
	}

	public Board(Move[] playerCards) {

		this.history = new Stack<Move>();
		this.availableActions = new LinkedList<Move>();
		this.playerCards = playerCards.clone();
		this.id = playerCards[0].toString();

		placeAnte();

		generateAvailableActions();
	}

	@SuppressWarnings("unchecked")
	public Board(Board board) {

		this.id = board.id;
		this.round = board.round;
		this.history = (Stack<Move>) board.history.clone();
		this.pot = board.pot;
		if (board.playerCards != null)
			this.playerCards = board.playerCards.clone();
		this.table = board.table == null ? null : new Move(board.table);
		this.currentPlayer = board.currentPlayer;
		this.availableActions = new LinkedList<Move>();

		generateAvailableActions();
	}

	@SuppressWarnings("unchecked")
	public Board(Board board, Move[] playerCards) {

		this.id = board.id;
		this.round = board.round;
		this.history = (Stack<Move>) board.history.clone();
		this.pot = board.pot;
		this.playerCards = playerCards.clone();
		this.table = board.table == null ? null : new Move(board.table);
		this.currentPlayer = board.currentPlayer;
		this.availableActions = new LinkedList<Move>();

		generateAvailableActions();
	}

	@Override
	public float[] evaluate(byte sign) {

		Move[] tempCards = playerCards.clone();
		Dealer dealer = new Dealer();
		LinkedList<Move> cardsOut = new LinkedList<Move>();

		System.out.println("***Welcome to evaluate***");

		float[] probabilities;
		int counter = 0;

		cardsOut.add(playerCards[currentPlayer - 1]);

		System.out.println("Current player: " + currentPlayer);

		System.out.println("First player's card " + playerCards[0]);
		System.out.println("Second player's card " + playerCards[1]);
		System.out.println("Table: " + table);

		if (table != null) {
			cardsOut.add(table);
		}

		probabilities = dealer.getCardProbabilitiesForCardsOut(cardsOut);

		System.out.println();
		for (int i = 0; i < probabilities.length; i++) {
			System.out.print(probabilities);
		}
		System.out.println();

		if (!history.isEmpty())
			if (history.peek().equals(new Move("f"))) {

				System.out.println("move  je f vracim " + (sign == this.currentPlayer ? pot : -pot));
				return sign == this.currentPlayer ? new float[] { pot } : new float[] { -pot };
			}

		float[] value = new float[3];

		for (Move card : dealer.getCardTypes()) {

			tempCards[2 - currentPlayer] = card;

			if (dealer.evaluate(tempCards[0], tempCards[1], table) == sign) {
				value[counter++] += probabilities[counter - 1] * pot;
			} else if (dealer.evaluate(tempCards[0], tempCards[1], table) == (3 - sign)) {
				value[counter++] -= probabilities[counter - 1] * pot;
			}

		}

		System.out.println("***Bye***");

		return value;
	}

	@Override
	public byte isTerminal() {

		if (!history.isEmpty() && history.peek().action.equals("f")) {
			return (byte) currentPlayer;
		}

		if (round == 3) {
			return new Dealer().evaluate(playerCards[0], playerCards[1], table);
		}

		return 0;
	}

	public int makeMove(Move move) {

		int value = 0;

		if (isValid(move)) {

			StringBuilder builder = new StringBuilder();

			builder.append(playerCards[2 - currentPlayer]);
			builder.append(id.substring(1));
			builder.append(".");
			builder.append(move);

			id = builder.toString();

			if (move.action.equals("b")) {
				pot += 2 * round;
				if (currentPlayer == 2) {
					gainForPlayer1 += 2 * round;
				}
			} else if (move.action.equals("r")) {
				pot += 4 * round;
				if (currentPlayer == 2) {
					gainForPlayer1 += 4 * round;
				}
			} else if (move.action.equals("c")) {
				pot += 2 * round;
				if (currentPlayer == 2) {
					gainForPlayer1 += 2 * round;
				}
				value = endPhase();
			} else if (move.action.equals("ch")) {
				if (!history.isEmpty() && history.peek().action.equals("ch")) {
					value = endPhase();
				}
			} else if (move.action.equals("f")) {
				endPhase();
			}
		} else {

			StringBuilder builder = new StringBuilder();

			table = move;

			builder.append(playerCards[0]);
			builder.append(id.substring(1));
			builder.append(".");
			builder.append(move);
			id = builder.toString();
			round++;
			currentPlayer = 2;
		}

		history.push(move);
		currentPlayer = (byte) (3 - currentPlayer);

		if (value == 3)
			history.push(new Move("end"));

		generateAvailableActions();

		return value;
	}

	public void reverseMove() {

		Move move = history.pop();

		if (move.action.equals("end")) {
			round--;
			reverseMove();
			return;
		}

		currentPlayer = (byte) (3 - currentPlayer);

		if (move.action.equals("b")) {
			pot -= 2 * round;
		} else if (move.action.equals("c")) {
			pot -= 2 * round;
		} else if (move.action.equals("r")) {
			pot -= 4 * round;
		} else if (move.action.equals("f")) {
			round = round == 1 ? round : round - 1;
		} else if (!move.action.equals("ch")) {
			round--;
			currentPlayer = (byte) (1 + history.size() % 2);
			table = null;
		}

		generateAvailableActions();

		this.id = this.id.substring(0, id.length() - (1 + move.action.length()));
	}

	protected void generateAvailableActions() {

		availableActions.clear();

		if (round < 3) {
			if (history.isEmpty() || history.peek().action.equals("ch")) {
				availableActions.add(new Move("b"));
				availableActions.add(new Move("ch"));
			} else if (history.peek().action.equals("b")) {
				availableActions.add(new Move("c"));
				availableActions.add(new Move("r"));
				availableActions.add(new Move("f"));
			} else if (history.peek().action.equals("r")) {
				availableActions.add(new Move("c"));
				availableActions.add(new Move("f"));
			} else if (history.peek().action.equals("c")) {
				availableActions.add(new Move("ch"));
				availableActions.add(new Move("b"));
			} else if (!history.peek().action.equals("f") && !history.peek().action.equals("end")) {
				availableActions.add(new Move("b"));
				availableActions.add(new Move("ch"));
			}
		}

	}

	private void placeAnte() {
		if (history.isEmpty()) {
			pot += 2;
			gainForPlayer1++;
		}

	}

	protected int endPhase() {

		if (round == 1) {
			return 2;
		}

		round++;

		return round;
	}

	public LinkedList<Move> getAvailableActions() {
		return availableActions;
	}

	public int getPot() {
		return pot;
	}

	public Move getLastMove() {

		if (history.isEmpty()) {
			return null;
		}

		return history.peek();
	}

	public boolean isValid(Move move) {

		if (history.isEmpty() || !history.peek().action.equals("end") || !history.peek().action.equals("f")) {
			for (Move availableMove : availableActions) {
				if (move.equals(availableMove))
					return true;
			}
		}

		return false;
	}

	@Override
	public LinkedList<Move> getSuccessors() {
		return availableActions;
	}

	@Override
	public byte getCurrentPlayer() {
		return currentPlayer;
	}

	public int getWinForPlayer(byte sign) {

		if (isTerminal() == sign) {
			return pot;
		}

		if (isTerminal() == 3 - sign) {
			return -pot;
		}

		return 0;
	}

}
